home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 July: Mac OS SDK / Dev.CD Jul 99 SDK1.toast / Development Kits / Mac OS / Thread Manager / Sample Applications / 68k Examples / Dining Philos (THINK⁄MPW) / PhiloThreads.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-17  |  8.0 KB  |  339 lines  |  [TEXT/MPS ]

  1. #ifndef THINK_C
  2. #include <QuickDraw.h>
  3. #include <OSUtils.h>
  4. #include <ThreadUtil.h>
  5. #endif
  6.  
  7. #include "ProtoStructs.h"
  8. #include "Globals.h"
  9.  
  10. /* Text replacement keeps me sane */
  11. #define RIGHT_FORK(thisOne) gForks[((thisOne->left_fork + 1) % kNumOfPhilosophizers)]
  12. #define LEFT_FORK(thisOne) gForks[thisOne->left_fork]
  13.  
  14.  
  15. /*
  16. ** If you want to play around and see the effects of using an ArraySemaphore for
  17. ** the footman, just uncomment the line below and check out how the Philosophizers
  18. ** are let in the room.
  19. **
  20. ** #define kUsingArraySemaphore    TRUE
  21. */
  22.  
  23. #ifdef kUsingArraySemaphore
  24. ArraySemaphorePtr    gFootman;
  25. #else
  26. short gNumEating;
  27. #endif
  28. /***********************************************************************************
  29. ******************************    THREAD ROUTINES    *******************************
  30. ***********************************************************************************/
  31.  
  32. /***********************************************************************************
  33. **
  34. ** Spawn each thread from the pool of newly created threads (you can change this 
  35. ** thread type to Preemptive, just make sure to change the init_threads routine, too
  36. */
  37. void spawn_threads()
  38. {
  39.     OSErr    anError;
  40.     short    index;
  41.     
  42.     ThreadBeginCritical();
  43.     for ( index = 0; index < kNumOfPhilosophizers; index++ )
  44.     {
  45.         anError = NewThread (kCooperativeThread, 
  46.                                 philo_actions, 
  47.                                 (void *)&(gPhilosophizer[index]),
  48.                                 (Size)0,
  49.                                 kUsePremadeThread, /* don't need the FPU context saved */
  50.                                 nil,
  51.                                 &(gPhilosophizer[index].theThread));
  52.         
  53.         if ( anError )
  54.             error("\pError in creating the New Thread (spawn_threads)", anError, kFatal);
  55.     }
  56.     ThreadEndCritical();
  57. }
  58.  
  59.  
  60. /***********************************************************************************
  61. **
  62. ** Do the think-eat thing kNumberOfIterations times.
  63. */
  64. pascal void *philo_actions(void *thisPhilo)
  65. {
  66.     short    index;
  67.     
  68.     for (index = 0; index < kNumberOfIterations; index++ )
  69.     {
  70.         think_for_a_while();
  71.         go_to_eat(thisPhilo);
  72.         pick_up_left_fork(thisPhilo);
  73.         pick_up_right_fork(thisPhilo);
  74.         eat_for_a_while(thisPhilo);
  75.         put_down_right_fork(thisPhilo);
  76.         put_down_left_fork(thisPhilo);
  77.         go_to_think(thisPhilo);
  78.     }
  79. }
  80.  
  81.  
  82. /***********************************************************************************
  83. **
  84. ** Think for a random amount of time and Yield while thinking
  85. */
  86. void think_for_a_while()
  87. {
  88.     short    counter;
  89.     short    timeToThink;
  90.  
  91. #ifndef THINK_C    
  92.     GetDateTime((unsigned long *)&qd.randSeed);
  93. #else
  94.     GetDateTime((unsigned long *)&randSeed);
  95. #endif
  96.     timeToThink = Random() % kThinkingTimeLimit;
  97.  
  98.     for ( counter = 0; counter < timeToThink; counter++ )
  99.         YieldToAnyThread()
  100.     ;
  101. }
  102.  
  103.  
  104. /***********************************************************************************
  105. **
  106. ** Take out the checkin_with_footman call to see a nice visual rep of deadlock
  107. ** you should also do the same with the checkout_with_footman call in go_to_think
  108. */
  109. void go_to_eat(philoPtr thisPhilo)
  110. {
  111.     thisPhilo->current_location = thisPhilo->waiting_location;
  112.     
  113.     checkin_with_footman();
  114.  
  115.     thisPhilo->current_location = thisPhilo->dining_location;
  116.     YieldToAnyThread();
  117. }
  118.  
  119.  
  120. /***********************************************************************************
  121. **
  122. ** Yield while eating
  123. */
  124. void eat_for_a_while(philoPtr thisPhilo)
  125. {
  126.     short    counter, timeToEat = Random() % kEatingTimeLimit;
  127.     
  128.     thisPhilo->current_location = thisPhilo->dining_location;
  129.     for (counter = 0; counter < timeToEat; counter++)
  130.         YieldToAnyThread()
  131.     ;
  132. }
  133.  
  134.  
  135. /***********************************************************************************
  136. **
  137. ** Take out checkout… call to see deadlock
  138. */
  139. void go_to_think(philoPtr thisPhilo)
  140. {
  141.     checkout_with_footman();
  142.     
  143.     thisPhilo->current_location = thisPhilo->thinking_location;
  144.     thisPhilo->fork_state = kNoForks;
  145.     YieldToAnyThread();
  146. }
  147.  
  148.  
  149. /***********************************************************************************
  150. *******************************    FORK ROUTINES    ********************************
  151. ***********************************************************************************/
  152.  
  153. /***********************************************************************************
  154. **
  155. ** Create the array of simple semaphores (in a global array)
  156. */
  157. void create_forks()
  158. {
  159.     short count;
  160.     OSErr    anError;
  161.  
  162.     for ( count = 0; count < kNumOfPhilosophizers; count++ )
  163.     {
  164.         anError = CreateSimpleSemaphore(&gForks[count]);
  165.         if ( anError )
  166.             error("\pProblem creating one of the forks", anError, kFatal);
  167.     }    
  168. }
  169.  
  170.  
  171. /***********************************************************************************
  172. **
  173. ** These next four routines either Get or Release the proper semaphore to
  174. ** do some eatin'.
  175. **
  176. ** Each philosophizer knows what its left fork is (part of its structure), and
  177. ** its right fork is just the one next to its left-- mod kNumOfPhilosophizers, 
  178. ** of course.
  179. */
  180. void pick_up_left_fork(philoPtr thisPhilo)
  181. {
  182.     OSErr    anError;
  183.     
  184.     anError = GetSimpleSemaphore(LEFT_FORK(thisPhilo));
  185.     
  186.     if ( anError )
  187.         error("\pProblem getting a Left Fork", anError, kFatal);
  188.  
  189.     thisPhilo->fork_state = kLeftFork;
  190.     YieldToAnyThread();
  191. }
  192.  
  193.  
  194. void pick_up_right_fork(philoPtr thisPhilo)
  195. {
  196.     OSErr    anError;
  197.     
  198.     anError = GetSimpleSemaphore(RIGHT_FORK(thisPhilo));
  199.     
  200.     if ( anError )
  201.         error("\pProblem getting an Right Fork", anError, kFatal);
  202.         
  203.     thisPhilo->fork_state = kBothForks;
  204.     YieldToAnyThread();
  205. }
  206.  
  207.  
  208. void put_down_right_fork(philoPtr thisPhilo)
  209. {
  210.     OSErr    anError;
  211.  
  212.     anError = ReleaseSimpleSemaphore(RIGHT_FORK(thisPhilo));
  213.     
  214.     if ( anError )
  215.         error ("\pProblem releasing the Right Fork", anError, kFatal);
  216.     
  217.     thisPhilo->fork_state = kLeftFork;
  218.     YieldToAnyThread();
  219. }    
  220.  
  221.  
  222. void put_down_left_fork(philoPtr thisPhilo)
  223. {
  224.     OSErr    anError;
  225.  
  226.     anError = ReleaseSimpleSemaphore(LEFT_FORK(thisPhilo));
  227.     
  228.     if ( anError )
  229.         error ("\pProblem releasing the Left Fork", anError, kFatal);
  230.  
  231.     thisPhilo->fork_state = kNoForks;
  232.     YieldToAnyThread();
  233. }
  234.  
  235.  
  236. /*ç
  237. **
  238. ** Get rid of each of the forks in the global array
  239. */
  240. void remove_forks()
  241. {
  242.     short    counter;
  243.     OSErr    anError;
  244.     
  245.     for ( counter = 0; counter < kNumOfPhilosophizers; counter++ )
  246.     {
  247.         anError = DeleteSimpleSemaphore(gForks[counter]);
  248.         
  249.         if ( anError )
  250.             error("\pProblem Deleting the Simple semaphore", anError, kFatal);
  251.     }
  252. }
  253.  
  254.  
  255. /***********************************************************************************
  256. *****************************    FOOTMAN ROUTINES    *******************************
  257. ***********************************************************************************/
  258.  
  259. /***********************************************************************************
  260. **
  261. ** Either set up the Array semaphore to let 'em in one at a time (preserving their
  262. ** order), or init the NumEating.
  263. */
  264. void create_footman()
  265. {
  266. #ifdef kUsingArraySemaphore
  267.  
  268.     OSErr anError = CreateArraySemaphore(kNumAllowedIn, &gFootman);
  269.     
  270.     if ( anError )
  271.         error ("\pProblem creating the Footman", anError, kFatal);
  272. #else
  273.  
  274.         gNumEating = 0;
  275. #endif
  276. }
  277.  
  278.  
  279. /***********************************************************************************
  280. **
  281. ** Either go for the semaphore (which will Yield until one is available), or
  282. ** go on through if there's room.  If there ain't room, Yield until there is.
  283. */
  284. void checkin_with_footman()
  285. {
  286. #ifdef kUsingArraySemaphore
  287.  
  288.     OSErr anError = GetArraySemaphore(gFootman);
  289.  
  290.     if ( anError )
  291.         error("\pProblem Checking in with the Footman", anError, kFatal);
  292. #else
  293.  
  294.     while ( gNumEating == kNumAllowedIn )
  295.         YieldToAnyThread()
  296.     ;
  297.  
  298.     gNumEating++;
  299. #endif
  300. }
  301.  
  302.  
  303. /***********************************************************************************
  304. **
  305. ** Release the semaphore, or decrement the NumEating.
  306. */
  307. void checkout_with_footman()
  308. {    
  309. #ifdef kUsingArraySemaphore
  310.  
  311.     OSErr anError = ReleaseArraySemaphore(gFootman);
  312.  
  313.     if ( anError )
  314.         error ("\pProblem Checking out with the Footman", anError, kFatal);
  315. #else
  316.  
  317.     gNumEating--;
  318. #endif
  319. }
  320.  
  321.  
  322. /***********************************************************************************
  323. **
  324. ** Throw out the Array semaphpore
  325. */
  326. void retire_footman()
  327. {
  328. #ifdef kUsingArraySemaphore
  329.  
  330.     OSErr anError;
  331.     
  332.     gFootman->numberWaiting = 0;        /* This makes me uneasy */
  333.  
  334.     anError = DeleteArraySemaphore(gFootman);
  335.     if ( anError )
  336.         error("\pProblem Retiring the Footman", anError, kFatal);
  337. #endif
  338. }
  339.